from object import Object
from eventServer import eventServer
from gameServer import gameServer
from menuServer import menuServer
from textureServer import textureServer
from copy import copy
from soundServer import sound

from OpenGL.GL import *
from OpenGL import GLUT

class GameRules(Object):
    def __init__(self):
        Object.__init__(self)
        
        self.defaultVar("time",0)
        self.defaultVar("maxScore",20)
        self.defaultVar("numZeroPlayers",0)
        self.defaultVar("numMaxPlayers",0)
        self.defaultVar("winner",None)
        self.defaultVar("minTime",0.0)
        self.defaultVar("maxTime",60.0)
        
        self.defaultVar("x",0)
        self.defaultVar("y",0)
        self.defaultVar("w",1)
        self.defaultVar("h",1)
        
        self.endMenuShown = False
        
        self.events = ['playerDied','playerStomp','playerTouch','startRound','overlayRender','oneNonZeroPlayer','oneNonMaxPlayer','update','onMinTime','onMaxTime','onItemDrop','onItemPickup','onItemCollide']
        for event in self.events:
            eventServer.register(event,self.dispatch)
            
        eventServer.register('respawnAllPlayers',self.respawnAllPlayers)
        eventServer.register('saveVals',self.saveVals)
        eventServer.register('incVals',self.incVals)
        eventServer.register('setScores',self.setScores)
        eventServer.register('incScore',self.incScore)
        eventServer.register('renderScores',self.renderScores)
        eventServer.register('nonZeroSpawnPlayer',self.nonZeroSpawnPlayer)
        eventServer.register('nonMaxSpawnPlayer',self.nonMaxSpawnPlayer)
        eventServer.register('endRound',self.endRound) #victory music hook
        eventServer.register('renderTime',self.renderTime)
        eventServer.register('updateTime',self.updateTime)
        eventServer.register('savePlayerVals',self.savePlayerVals)
        eventServer.register('incPlayerVals',self.incPlayerVals)
        eventServer.register('renderVal',self.renderVal)
        eventServer.register('printVals',self.printVals)
        
    def dispatch(self, cmd, args):
        if not self.endMenuShown and self.hasVar(cmd):
            for event, eventArgs in self.sortEvents(self.getVar(cmd).items()):
                pullArgs = copy(args)
                
                for name, val in eventArgs.iteritems():
                    if type(val) == str and val and val[0] == '_' and args.has_key(val[1:]):
                        pullArgs[name] = self.getArg(args,val[1:],None)
                    else:
                        pullArgs[name] = val
                        
                for name, val in pullArgs.iteritems():
                    if type(val) == str and '.' in val:
                        #print "replacing", name, val
                        pullArgs[name] = self.getArg(pullArgs,name,val)
                        #print "new val", pullArgs[name]
                    else:
                        pullArgs[name] = val
                    
                        
                pull = True
                #if event.split('_')[0] in ['savePlayerVals','saveVals']:
                    #print "consider", event
                    
                debug = pullArgs.has_key('debug') and pullArgs['debug']
                        
                for name, val in pullArgs.iteritems():
                    if name.startswith('cond'):
                        lookUpArgs = copy(pullArgs)
                        lookUpArgs.update(val)
                        
                        val1 = self.getArg(lookUpArgs,'val1',True)
                        compType = self.getArg(lookUpArgs,'type','eq')
                        val2 = self.getArg(lookUpArgs,'val2',True)
                        
                        if not self.evalCond(val1,compType,val2):
                            #if event.split('_')[0] in ['savePlayerVals','saveVals']:
                            if debug:
                                print "no pull cond", name, val1, compType, val2
                            pull = False
                        #else:
                            #if event.split('_')[0] in ['savePlayerVals','saveVals']:
                                #print "cond", name, "true", val1, compType, val2
                        
                if pull:
                    #if event.split('_')[0] in ['savePlayerVals','saveVals']:
                        #print "pull", event, pullArgs
                        
                    if debug:
                        print "pull", event, pullArgs
                    
                    eventServer.pull(event.split('_')[0],pullArgs)
                    
                elif debug:
                    print "no pull", event, pullArgs
                    
    def evalCond(self, val1, type, val2):
        if type == 'eq':
            return val1 == val2
        elif type == 'lt':
            return val1 < val2
        elif type == 'lte':
            return val1 <= val2
        elif type == 'gt':
            return val1 > val2
        elif type == 'gte':
            return val1 >= val2
        else:
            return True
                
    def sortEvents(self, events):
        def comp(e1, e2):
            if not e1[1].has_key('order'):
                return 1
            elif not e2[1].has_key('order'):
                return -1
            else:
                return e1[1]['order'] - e2[1]['order']
            
        events.sort(comp)
        
        return events
            
    def incPlayerVals(self, cmd, args):
        player = gameServer.getObject('player%d' % self.getArg(args,'player',None))
        if player:
            amount = self.getArg(args,'amount',1)
            factor = self.getArg(args,'factor',1)
            for name in [s.strip() for s in self.getArg(args,'valsToInc','').split(',')]:
                if player.hasVar(name):
                    player.setVar(name,player.getVar(name)+amount*factor)
        
    def savePlayerVals(self, cmd, args):
        player = gameServer.getObject('player%d' % self.getArg(args,'player',None))
        if player:
            for name in [s.strip() for s in self.getArg(args,'valsToSave','').split(',')]:
                val = self.getArg(args,name,None)
                print "savePlayerVal", player.getVar('name'), name, val
                player.setVar(name,val)
                
    def saveVals(self, cmd, args):
        if args.has_key('valsToSave'):
            vals = args['valsToSave']
            for name in [s.strip() for s in vals.split(',')]:
                val = self.getArg(args,name,None)
                #print "saveVal", name, val
                self.setVar(name,val)
                
    def incVals(self, cmd, args):
        amount = self.getArg(args,'amount',1)
        factor = self.getArg(args,'factor',1)
        for name in [s.strip() for s in self.getArg(args,'valsToInc','').split(',')]:
            if self.hasVar(name):
                self.setVar(name,self.getVar(name)+amount*factor)
                
    def updateTime(self, cmd, args):
        amount = self.getArg(args,'amount',1.0)
        self.setVar("time",self.getVar("time") + args['dtime'] * amount)
        
        winnerComp = self.getArg(args,'winnerComp','compMax')
        
        if self.getVar("time") <= self.getVar("minTime"):
            self.setVar("time",self.getVar("minTime"))
            winner = self.getWinner(winnerComp)
            eventServer.pull('onMinTime',{"winner":winner})
            
        if self.getVar("time") >= self.getVar("maxTime"):
            self.setVar("maxTime",self.getVar("maxTime"))
            winner = self.getWinner(winnerComp)
            eventServer.pull('onMaxTime',{"winner":winner})
            
    def getWinner(self, comp):
        retWinner = winner = None
        score = None
        
        for i in range(self.getVar("numPlayers")):
            playerName = 'player%d' % i
            player = gameServer.getObject(playerName)
            if player:
                playerScore = player.getVar("score")
                if comp == 'compMin' and (score == None or playerScore < score):
                    score = playerScore
                    retWinner = winner = i + 1
                elif comp == 'compMax' and (score == None or playerScore > score):
                    score = playerScore
                    retWinner = winner = i + 1
                elif score != None and playerScore == score:
                    if type(retWinner) == tuple:
                        retWinner += (i+1,)
                    else:
                        retWinner = (retWinner,i+1)
        return retWinner
        
    def endRound(self, cmd, args):
        sound.play('victory', True)
        eventServer.pull('showMenu',{'menu':'endRoundMenu'})
        menu = gameServer.getObject('endRoundMenu')
        self.endMenuShown = True
        if menu and menu.hasVar('widgets'):
            if menu.getVar("widgets").has_key('text_win'):
                text = "Player %s wins!" % str(self.getVar("winner"))
                menu.getVar("widgets")['text_win']['text'] = text
        
    def respawnAllPlayers(self, cmd, args):
        numPlayers = self.getArg(args, 'numPlayers', 4)
        for i in range(numPlayers):
            #eventServer.pull('despawnPlayer',{'player':i})
            eventServer.pull('spawnPlayer',{'player':i})
            
    def setScores(self, cmd, args):
        score = self.getArg(args,'score',0)
        for i in range(self.getVar("numPlayers")):
            playerName = 'player%d' % i
            player = gameServer.getObject(playerName)
            if player:
                player.setVar("score",score)
                
    def incScore(self, cmd, args):
        playerNum = self.getArg(args, 'player', 0)
        amount = self.getArg(args, 'amount', 1)
        playerName = 'player%d' % playerNum
        player = gameServer.getObject(playerName)
        if player:
            player.setVar("score",player.getVar("score") + amount)
            
            if player.getVar("score") <= 0:
                eventServer.pull("playerZeroScore",{"player":playerNum})
                self.setVar("numZeroPlayers",self.getVar("numZeroPlayers")+1)
                if self.getVar("numZeroPlayers") >= self.getVar("numPlayers") - 1:
                    
                    winner = None
                    for i in range(self.getVar("numPlayers")):
                        playerName = 'player%d' % i
                        playeri = gameServer.getObject(playerName)
                        if playeri and playeri.getVar("score") > 0:
                            winner = i + 1
                    
                    eventServer.pull('oneNonZeroPlayer',{'winner':winner})
                
            if player.getVar("score") >= self.getVar("maxScore"):
                eventServer.pull("playerMaxScore",{"player":playerNum})
                self.setVar("numMaxPlayers",self.getVar("numMaxPlayers")+1)
                if self.getVar("numMaxPlayers") >= self.getVar("numPlayers") - 1:
                    
                    winner = None
                    for i in range(self.getVar("numPlayers")):
                        playerName = 'player%d' % i
                        playeri = gameServer.getObject(playerName)
                        if playeri and playeri.getVar("score") < self.getVar("maxScore"):
                            winner = i + 1
                    
                    eventServer.pull('oneNonMaxPlayer',{'winner':winner})
                    
    def nonMaxSpawnPlayer(self, cmd, args):
        playerName = 'player%d' % self.getArg(args,'player',None)
        player = gameServer.getObject(playerName)
        if player:
            if player.getVar("score") < self.getVar("maxScore"):
                eventServer.pull('spawnPlayer',args)
            
    def nonZeroSpawnPlayer(self, cmd, args):
        playerName = 'player%d' % self.getArg(args,'player',None)
        player = gameServer.getObject(playerName)
        if player:
            if player.getVar("score") > 0:
                eventServer.pull('spawnPlayer',args)
            
    def renderScores(self, cmd, args):
        x = self.getArg(args, 'x', 0.0, False)
        y = self.getArg(args, 'y', 0.0, False)
        w = self.getArg(args, 'w', 1.0, False)
        h = self.getArg(args, 'h', 0.1, False)
        color = self.getArg(args, 'color', (1,1,1))
        font = self.getArg(args, 'font', '')
        comp = self.getArg(args, 'winnerComp', 'compMax')
        showTextures = self.getArg(args, 'showTextures', True)
        textureSize = self.getArg(args, 'textureSize', 0.1)
        
        winner = self.getWinner(comp)
        
        numPlayers = self.getVar("numPlayers")
        for i in range(numPlayers):
            playerName = 'player%d' % i
            player = gameServer.getObject(playerName)
            if player:
                score = player.getVar("score")
                texture = player.getVar("texture")
            else:
                score = None
                texture = None
            text = "Player %d: %.1f" % (i+1, score)
            
            rat = float(i+1) / float(numPlayers+1)
            tx = x + rat * w
            ty = y + h/2.0
            
            if (type(winner) == int and i+1 == winner) or (type(winner) == tuple and i+1 in winner):
                playerColor = (1,0,0)
            else:
                playerColor = color
            
            self.renderText(tx,ty,text,playerColor,font)
            
            if showTextures and texture:
                texx = tx - textureSize/2.0
                texy = ty - textureSize/2.0
                
                self.renderRect(texx,texy,textureSize,textureSize,texture)
            
    def renderTime(self, cmd, args):
        x = self.getArg(args, 'x', 0.5, False)
        y = self.getArg(args, 'y', 0.1, False)
        color = self.getArg(args, 'color', (1,1,1))
        font = self.getArg(args, 'font', '')
        text = "Time: %.1f" % self.getVar("time")
        self.renderText(x,y,text,color,font)

    def convertAbsCoord(self, x, y):
        return float(x) * gameServer.screenw, float(y) * gameServer.screenh
    
    def convertCoordToScreen(self, x, y):
        nx,ny = self.convertCoord(x,y)
        return self.convertAbsCoord(nx,ny)
    
    def convertCoord(self, x, y):
        nx = self.getVar("x") + float(x) * self.getVar("w")
        ny = self.getVar("y") + float(y) * self.getVar("h")
        return nx,ny
    
    def renderVal(self, cmd, args):
        x = self.getArg(args,'x',0.5,False)
        y = self.getArg(args,'y',0.5,False)
        valName = self.getArg(args,'val',None)
        val = self.getArg(args,valName,None)
        prefix = self.getArg(args,'prefix','')
        color = self.getArg(args,'color',(1,1,1))
        font = self.getArg(args,'font','')
        format = self.getArg(args,'format','%s')
        textFormat = '%s ' + format
        text = textFormat % (str(prefix),val)
        
        self.renderText(x,y,text,color,font)
    
    def renderText(self, rx, ry, text, color, font):
        """
            fonts are:
            times_roman_[10|24]
            helvetica_[10|12|18]
        """
        
        if menuServer.anyMenusShown():
            return
        
        x,y = self.convertCoordToScreen(rx,ry)
        
        if not color:
            color = (1,1,1)
            
        glColor3f(color[0],color[1],color[2])
        
        fontName = "GLUT_BITMAP_" + font.upper()
        if GLUT.__dict__.has_key(fontName):
            glutFont = GLUT.__dict__[fontName]
        else:
            glutFont = GLUT.GLUT_BITMAP_HELVETICA_18

        try:            
            height = GLUT.glutBitmapHeight(glutFont)
        except:
            height = 18
        width = 0
        for ch in text:
            width += GLUT.glutBitmapWidth(glutFont,ord(ch))
            
        glPushMatrix()
        
        glTranslatef(0,0,0.01)
        glRasterPos(x-width/2.0,y+height/2.0-5,0)
        
        for ch in text:
            GLUT.glutBitmapCharacter(glutFont,ord(ch))
            
        glPopMatrix()
        
        glColor3f(1,1,1)
        
    def renderRect(self, px, py, pw, ph, texture):
        if menuServer.anyMenusShown():
            return
        
        x,y = self.convertCoordToScreen(px,py)
        w,h = self.convertCoordToScreen(px+pw,py+ph)
        
        if texture and not textureServer.bindTexture(texture,True):
            return False
        
        glBegin(GL_QUADS)
        
        glTexCoord2f(0,0)
        glVertex2f(x,y)
        glTexCoord2f(0,1)
        glVertex2f(x,h)
        glTexCoord2f(1,1)
        glVertex2f(w,h)
        glTexCoord2f(1,0)
        glVertex2f(w,y)
        
        glEnd()
        
        textureServer.unbindTexture()
        return True
    
    def printVals(self, cmd, args):
        print cmd, args
        
    def getArg(self, args, name, default, selfLookUp = True):
        if args.has_key(name):
            val = args[name]
        elif selfLookUp and self.hasVar(name):
            val = self.getVar(name)
        else:
            val = default
            
        if type(val) == str and val:
            if val[0] == '_':
                newVal = self.getArg(args,val[1:],None,selfLookUp)
                if newVal != None:
                    return newVal
            if '.' in val:
                objName = val[:val.find('.')]
                varName = val[val.find('.')+1:]
                
                if ',' in objName:
                    idName = objName[objName.find(',')+1:]
                    id = self.getArg(args,idName,None)
                    objName = objName[:objName.find(',')]
                    
                    #print "idName", idName, "id", id, "from", args
                    objName += str(id)
                    
                #print "lookup", objName, varName
                
                if gameServer.hasObject(objName):
                    obj = gameServer.getObject(objName)
                    if obj.hasVar(varName):
                        var = obj.getVar(varName)
                        #print "lookup got", val, var
                        return var
                
        return val
        
